#ifndef _TEXTURE_SOLIDNOISE_H_
#define _TEXTURE_SOLIDNOISE_H_

#include <cmath>
#include "../Basis/Vector3.h"

#define PERLIN_VECTOR_NUM	16


//	the complete description fo Perlin Solid Noise can be found in chapter 5 of "Realistic Ray Tracing"
class SolidNoise
{
public:
	SolidNoise();
	float noise(const Vector3& p) const;
	float turbulence(const Vector3& p, int depth) const;
	float dturbulence(const Vector3& p, int depth, float d) const;
	float omega(float t) const;
	Vector3 gamma(int i , int j, int k) const;
	int intGamma(int i, int j) const;
	float knot(int i, int j, int k, Vector3& v) const;

private:
	Vector3 grad[PERLIN_VECTOR_NUM];
	int phi[PERLIN_VECTOR_NUM];
};

//	omega is the cubic weight function
//	assume t is in [-1, 1]
inline float SolidNoise::omega(float t) const
{
	t = (t > 0.0f) ? t : -t;
	float triple = t * t * t;
	return triple * (-6.0f * t * t + 15.0f * t - 10.0f) + 1.0f;
}


inline Vector3 SolidNoise::gamma(int i , int j, int k) const
{
	int idx;
	idx = phi[abs(k) % PERLIN_VECTOR_NUM];
	idx = phi[abs(j + idx) % PERLIN_VECTOR_NUM];
	idx = phi[abs(i + idx) % PERLIN_VECTOR_NUM];
	return grad[idx];
}

inline float SolidNoise::knot(int i, int j, int k, Vector3& v) const
{
	return (omega(v.x()) * omega(v.y()) * omega(v.z()) * dot(gamma(i, j, k), v));
}

inline int SolidNoise::intGamma(int i, int j) const
{
	int idx;
	idx = phi[abs(j) % PERLIN_VECTOR_NUM];
	idx = phi[abs(i + idx) % PERLIN_VECTOR_NUM];
	return idx;
}

#endif